package se.teamscape.client.presenter;

import java.util.Collections;
import java.util.List;

import net.customware.gwt.presenter.client.EventBus;
import net.customware.gwt.presenter.client.PresenterRevealedEvent;
import net.customware.gwt.presenter.client.PresenterRevealedHandler;
import net.customware.gwt.presenter.client.widget.WidgetPresenter;

import com.google.gwt.user.client.ui.Widget;

/**
 * BaseContainerPresenter is basically a replacement for
 * WidgetContainerPresenter that
 * adds support for location aware presenters.
 * 
 * @author Andreas Borglin
 */
public abstract class BaseContainerPresenter<T extends BaseContainerPresenter.Display> extends BasePresenter<T> {

    public interface Display extends BasePresenter.Display {

        void showWidget(Widget widget, WidgetProperties properties);

        void removeWidget(Widget w);

        void removeAll();
    }

    /**
     * Widget properties
     * 
     * @author Andreas Borglin
     * 
     */
    public static class WidgetProperties {

        public int mLocation;
        public int mIndex;
        public int mSize;

        public WidgetProperties(int loc, int idx, int size) {
            mLocation = loc;
            mIndex = idx;
            mSize = size;
        }
    }

    private final List<WidgetPresenter<?>> mPresenters;
    private WidgetPresenter<?> mCurrentPresenter;

    public BaseContainerPresenter(T display, EventBus eventBus, WidgetPresenter<?>... presenters) {

        super(display, eventBus);

        mPresenters = new java.util.ArrayList<WidgetPresenter<?>>();
        Collections.addAll(mPresenters, presenters);

    }

    protected boolean addPresenter(WidgetPresenter<?> presenter) {
        if (!isBound()) {
            mPresenters.add(presenter);
            return true;
        }
        return false;
    }

    protected void removePresenter(WidgetPresenter<?> presenter) {
        presenter.unbind();
        mPresenters.remove(presenter);
    }

    protected WidgetPresenter<?> getCurrentPresenter() {
        return mCurrentPresenter;
    }

    protected int indexOf(WidgetPresenter<?> presenter) {
        return mPresenters.indexOf(presenter);
    }

    @Override
    protected void onBind() {
        onBind(true);
    }

    protected void onBind(boolean addHandler) {

        // Let the presenter decide if we should listen to events
        if (addHandler) {
            registerHandler(eventBus.addHandler(PresenterRevealedEvent.getType(), new PresenterRevealedHandler() {
                public void onPresenterRevealed(PresenterRevealedEvent event) {
                    if (mPresenters.contains(event.getPresenter())) {
                        showPresenter((WidgetPresenter<?>) event.getPresenter());
                        revealDisplay();
                    }
                }
            }));
        }

        for (WidgetPresenter<?> presenter : mPresenters) {
            presenter.bind();
        }

    }

    @Override
    protected void onLazyBind() {
        // No op for most container presenters
    }

    @Override
    protected void onRevealDisplay() {
        // No op by default here
    }

    @Override
    protected void onUnbind() {

        mCurrentPresenter = null;
        display.removeAll();
        for (WidgetPresenter<?> presenter : mPresenters) {
            presenter.unbind();
        }

    }

    /*
     * Container views that are constantly present from start up
     * are revealed explicitly instead of as a result of an event.
     */
    protected void showAllPresenters() {

        for (WidgetPresenter<?> presenter : mPresenters) {
            presenter.revealDisplay();
            showPresenter(presenter);
        }
    }

    @SuppressWarnings("unchecked")
    protected void showPresenter(WidgetPresenter<?> presenter) {

        WidgetProperties properties = null;
        if (presenter instanceof LocationAwarePresenter) {
            properties = ((LocationAwarePresenter) presenter).getWidgetProperties();
        }

        display.showWidget(presenter.getDisplay().asWidget(), properties);
        mCurrentPresenter = presenter;
    }

}
